#include "raytracer.h"

RayTracer::RayTracer(unsigned int width, unsigned int height, unsigned int _level, bool antialiasing) :
    camera() , film(width,height,(antialiasing?2:1)), scene(), level(_level)
{
    //load(sceFile);
}


RayTracer::~RayTracer()
{
    //std::cout<<"~RayTracer();"<<std::endl;
}


void RayTracer::setCameraSettings(double x, double y, double z, double dx, double dy, double dz, double ax, double ay)
{
    camera.setPosition(Point3D(x,y,z));
    camera.setSceneCenter(Point3D(dx,dy,dz));
    camera.setViewAngles(ax,ay);
}


void RayTracer::setAnaglyphSettings(const Color &, const Color &, const double &)
{
}

void RayTracer::render(const std::string &outFile,const Color &mask,const double &eyeDist) const
{

    Color pixel;
    Ray ray;
    unsigned int y(0),i(0), width(film.getWidth()), height(film.getHeight()), level_max;
    double * dst(film.getData()), dx, dy, ax, ay;
    Vector3D Z(camera.getViewVector());Z.normalize();
    Vector3D Y(0.0,1.0,0.0);

    Vector3D X(Y.getY()*Z.getZ()-Y.getZ()*Z.getY(),
               Y.getZ()*Z.getX()-Y.getX()*Z.getZ(),
               Y.getX()*Z.getY()-Y.getY()*Z.getX());X.normalize();

    Point3D cameraPos = camera.getPosition()+(X*eyeDist);
    //camera.setPosition(cameraPos); nope!!!

    Z = (camera.getSceneCenter()-cameraPos);Z.normalize();
    X = Vector3D(Y.getY()*Z.getZ()-Y.getZ()*Z.getY(),
                 Y.getZ()*Z.getX()-Y.getX()*Z.getZ(),
                 Y.getX()*Z.getY()-Y.getY()*Z.getX());
    X.normalize();

    Y=Vector3D(Z.getY()*X.getZ()-Z.getZ()*X.getY(),
               Z.getZ()*X.getX()-Z.getX()*X.getZ(),
               Z.getX()*X.getY()-Z.getY()*X.getX());
    Y.normalize();

    //printf("X : [%f ; %f ; %f]\n",X.getX(),X.getY(),X.getZ());
    //printf("Y : [%f ; %f ; %f]\n",Y.getX(),Y.getY(),Y.getZ());
    //printf("Z : [%f ; %f ; %f]\n",Z.getX(),Z.getY(),Z.getZ());

    ay = -((camera.getHeightAngle()/2.0)*M_PI/180.0);
    ax = ((camera.getWidthAngle()/2.0)*M_PI/180.0);

    ray.setOrigin(cameraPos);

    for(; y < height ; y++)
    {
        dy = (y-(height/2.0))/(height/2.0);
        for( i=0 ; i < width ; i++)
        {
            level_max=level;
            dx = (i-(width/2.0))/(width/2.0); // compris entre -1 et 1
            ray.setDirection(Z + X*(dx*tan(ax)) + Y*(dy*tan(ay)));
            scene.rayTracering(ray,pixel,level_max);
            *(dst++) += pixel.getRed()   * mask.getRed();
            *(dst++) += pixel.getGreen() * mask.getGreen();
            *(dst++) += pixel.getBlue()  * mask.getBlue();
        }
    }
    film.save(outFile);
}


void RayTracer::load(const std::string &sceFile)
{
    SceLoader loader(sceFile,&scene);
    double * ptr(loader.cameraInfos);
    setCameraSettings(*(ptr),*(ptr+1),*(ptr+2),*(ptr+3),*(ptr+4),*(ptr+5),*(ptr+6),*(ptr+7));
}
